﻿using Jayrock.Json;
using Jayrock.Json.Conversion;
using open_api_sdk_csharp.com.chinaums.open.api.constants;
using open_api_sdk_csharp.com.chinaums.open.api.internals.utils.convertors;
using open_api_sdk_csharp.com.chinaums.open.api.internals.utils.http;
using open_api_sdk_csharp.request;
using open_api_sdk_csharp.response;
using System;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
//token 获取相关工具类
namespace open_api_sdk_csharp.com.chinaums.open.api.internals.utils
{
    public class TokenUtils
    {
        public static string generateSignature(string appId, string timestamp,
                                          string nonce, string appKey)
        {
            String plaintext = appId + timestamp + nonce + appKey;
            try
            {
                var strRes = Encoding.Default.GetBytes(plaintext);
                HashAlgorithm iSha = new SHA1CryptoServiceProvider();
                strRes = iSha.ComputeHash(strRes);
                var signature = new StringBuilder();
                foreach (byte iByte in strRes)
                {
                    signature.AppendFormat("{0:x2}", iByte);
                }
                return signature.ToString();
            }
            catch (Exception e)
            {
                OpenApiLogger.logError(e.Message);
            }
            return null;
        }
        public static TokenResponse getToken(OpenApiContext context)
        {
            int retry = 0;
            ConfigBean configBean = context.ConfigBean;
            TokenResponse acquiredToken = null;
            if (isTokenValid(context.CurrentToken) && !isTokenTimeout(context.CurrentToken))
            {
                return context.CurrentToken;
            }
            while (retry++ < configBean.TokenAcquireReties)
            {
                acquiredToken = acquireAccessToken(context);
                if (null != acquiredToken)
                {
                    break;
                }
                else if (retry < configBean.TokenAcquireReties)
                {
                    try
                    {
                        Thread.Sleep(200);
                    }
                    catch (Exception e)
                    {
                        OpenApiLogger.logError(" 重试token申请出错:" + e.Message);
                    }
                }
                else
                {
                    OpenApiLogger.logError(" 申请token超过重试次数 bye-bye");
                    break;
                }
            }
            return acquiredToken;
        }
        private static TokenResponse acquireAccessToken(OpenApiContext context)
        {
            String appId = context.AppId;
            String appKey = context.AppKey;
            ConfigBean configBean = context.ConfigBean;
            TokenRequest tokenRequest = new TokenRequest(appId, appKey);
            OpenModelParser parser = new OpenModelParser();
            JsonObject jsonobject = parser.serializeRequestObject(tokenRequest);
            string request = JsonConvert.ExportToString(jsonobject);
            string url = context.OpenServUrl + "" + configBean.Version + "" + configBean.TokenServiceCode;
            String response = HttpTransport.Instance.doPost(configBean.IsProd, url, null, request);
            Converter<TokenResponse> converter = new JsonConverter<TokenResponse>();
            TokenResponse tokenResponse = converter.toResponse(response, typeof(TokenResponse));
            tokenResponse.effectTime = DateTime.Now;
            tokenResponse.timeout = tokenResponse.expiresIn;
            tokenResponse.aheadInterval = configBean.TokenAcquireAheadInterval;
            return tokenResponse;
        }
        private static bool isTokenValid(TokenResponse tokenBean)
        {
            return (null != tokenBean
                    && !string.IsNullOrEmpty(tokenBean.accessToken)
                    && null != tokenBean.effectTime
                    && tokenBean.timeout > 0
                    && tokenBean.aheadInterval > 0 && tokenBean.timeout > tokenBean
                    .aheadInterval);
        }

        private static bool isTokenTimeout(TokenResponse tokenBean)
        {
            TimeSpan span = DateTime.Now - tokenBean.effectTime;
            int elapseInterval = span.Minutes;
            int maxEffectiveInterval = tokenBean.timeout - tokenBean.aheadInterval;
            bool isTimeout = (elapseInterval > maxEffectiveInterval);
            if (isTimeout)
            {
                OpenApiLogger.logError("exception:token过期了");
            }
            return isTimeout;
        }
        private static byte[] ConvertHexStringToByteArray(string hexString)
        {
            if (hexString.Length % 2 != 0)
            {
                throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "The binary key cannot have an odd number of digits: {0}", hexString));
            }
            byte[] HexAsBytes = new byte[hexString.Length / 2];
            for (int index = 0; index < HexAsBytes.Length; index++)
            {
                string byteValue = hexString.Substring(index * 2, 2);
                HexAsBytes[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
            }

            return HexAsBytes;
        }
    }
}